home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- //
- // Sample Name: DataRelay Sample
- //
- // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
- //
- //-----------------------------------------------------------------------------
-
-
- Description
- ===========
- The DataRelay is similar to SimplePeer but differs by sending a single
- target (or everyone) a packet of data with options specified in the
- dialog's UI. It uses a worker thread to process received data, and
- uses the ReturnBuffer() API so that no copying of the received buffers
- is done.
-
- Path
- ====
- Source: DXSDK\Samples\Multimedia\DirectPlay\DataRelay
-
- Executable: DXSDK\Samples\Multimedia\DirectPlay\Bin
-
- User's Guide
- ============
- Host or connect to a session in the same manner as explained in SimplePeer.
- When the main dialog appears select the target, size, rate, and timeout values.
- Then click "Push to Send". This will send a packet of data to the target as
- the rate specified with the specified size. Use the "Connection Info" dropdown
- to specify a target to gather connection info on periodically.
-
- Programming Notes
- =================
- The DataRelay sample is very similar in form to the SimplePeer sample. For
- detailed programming notes on the basics this sample, refer to Programming
- Notes section of the SimplePeer sample.
-
- The DataRelay differs by sending a single target (or everyone) a packet of
- data with options specified in the dialog's UI.
-
- When the "Push to Send" button is clicked, then win32 timer is created
- that goes off every number of ms according to the UI.
-
- * Upon the WM_TIMER labeled TIMERID_NETWORK, it calls SendNetworkData().
- 1. It creates a app defined struct, GAMEMSG_DATA_xxx on the heap.
- The struct derives from GAMEMSG_GENERIC. GAMEMSG_GENERIC contains a
- packet type field so that the reciever and identify this app defined
- packet, and it contains a packet ID field. This field is sequential
- and is displayed to the user whenever a packet is received. The struct
- is created on the heap, since will use the DPNSEND_NOCOPY when calling
- SendTo() below. The struct is filled with random data, however a real
- app would typically send player and world state data here.
- 2. It then creates a GAMEMSG_DATA_NODE which is then handed off to the
- app worker thread. That thread will process the node, and
- then update the UI to show that a packet was sent. It is handed off
- by adding the node to a linked list. Since the worker thread also
- accesses the linked list, we enter a critical section before adding the
- node and leave it afterward.
- 3. A DPN_BUFFER_DESC is then filled out passing in a pointer to the
- app defined struct created above.
- 4. IDirectPlay8Peer::SendTo is called passing in the DPN_BUFFER_DESC, thereby
- sending the app defined struct, GAMEMSG_DATA_xxx. We call SendTo with
- the flags DPNSEND_NOLOOPBACK | DPNSEND_NOCOPY. DPNSEND_NOLOOPBACK tells
- DirectPlay to not to send the buffer to us, and DPNSEND_NOCOPY means that
- DirectPlay should not copy the buffer. When the DPNSEND_NOCOPY is used,
- the app itself owns the buffer, and the buffer must be on the heap.
- When the DPN_MSGID_SEND_COMPLETE comes in, we will delete the buffer.
- 5. The event, g_hDPDataAvailEvent, is set telling the worker thread that
- there is data (a message to say that a packet was sent), is ready to
- be processed now.
-
- * Handle DirectPlay system messages. See DirectPlayMessageHandler()
- The DataRelay handles the typical messages as described in the
- SimplePeer programming notes, and in addition:
-
- - Upon DPN_MSGID_RECEIVE
- 1. It casts the pReceiveMsg->pReceiveData to a GAMEMSG_GENERIC*.
- 2. It then switches off the GAMEMSG_GENERIC's dwType.
- 3. If its a GAME_MSGID_GAMEPACKET, then it creates and fills out
- a GAMEMSG_DATA_NODE. This node is then handed to a worker thread
- so it can be processed outside of the DirectPlay message handler.
- This is important since it keeps the DirectPlay threads working at
- full speed.
- 4. After the node is added to the linked list using a critical section
- to lock, it returns DPNSUCCESS_PENDING. This is important since
- it tells DirectPlay that ownership of the buffer
- has been transferred to the application, and so DirectPlay will
- neither free nor modify it until ownership is returned
- to DirectPlay through the ReturnBuffer() call.
-
- - Upon DPN_MSGID_SEND_COMPLETE
- 1. It checks the pSendCompleteMsg->hResultCode for DPNERR_TIMEDOUT.
- 2. If this occurs then it creates a new GAMEMSG_DATA_NODE with dwType
- set to DATA_TYPE_NETPACKET_TIMEOUT. This will is passed to the
- worker thread. The worker thread will process this node, and
- post a message to the dialog saying that the message timed out.
- A realistic application would want to take the appropriate steps here,
- such as resending new data or other measures.
- 3. It deletes the buffer from the heap since we specified, DPNSEND_NOCOPY,
- so the buffer on the heap belows the app and it must clean it up.
-
- * The worker thread. See ProcessNetDataProc()
- - Upon the g_hDPDataAvailEvent
- 1. When the event is signaled, then new data can be found in the
- linked list, g_DataHead. So it calls ProcessData().
- 2. ProcessData() first enters the critical section, g_csDataList, so
- that the other threads don't modify the linked list while it is
- processing data. It leaves this critical section at the end of the
- loop. Typically better locking mechanisms would be used so that the
- other threads (as well as the DirectPlay message handler threads)
- aren't blocked while data is processed on this thread.
- 3. It runs through the linked list, processing each node. For this
- simple sample all it does is posting a message to the dialog thread,
- containing a string for the dialog to display.
- 4. After it is done processing the node, it calls
- IDirectPlay8Peer::ReturnBuffer() so that DirectPlay can free
- buffer that it passed us in DPN_MSGID_RECEIVE.
-
-
-
-
-
-
-
-
-
-